package com.cs.service.impl;

import com.cs.config.RabbitMqConfig;
import com.cs.domain.*;
import com.cs.domain.vo.ApplicationVO;
import com.cs.domain.vo.ExpertEducateVO;
import com.cs.mapper.CsApplicationsMapper;
import com.cs.service.CSCodeRulesService;
import com.cs.service.ICsApplicationsService;
import com.cs.util.CSRuleCode;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.rabbitmq.client.Channel;
import com.ruoyi.common.core.domain.R;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static com.cs.util.CSRuleCreate.createCode;

@Service
public class CsApplicationsServiceImpl implements ICsApplicationsService {
    @Autowired
    private CsApplicationsMapper csApplicationsMapper;

    @Autowired
    private CSCodeRulesService service;

    @Autowired
    private RabbitTemplate template;
    @Autowired
    private ObjectMapper objectMapper;


    @Override
    public Integer addSupplier(CsSupplier csSupplier) {
        return csApplicationsMapper.addSupplier(csSupplier);
    }

    @Override
    public Integer addRelation(Integer hid, Long userId) {
        return csApplicationsMapper.addRelation(hid, userId);
    }

    /**
     * 查询抽取申请
     *
     * @param xid 抽取申请主键
     * @return 抽取申请
     */
    @Override
    public CsApplications selectCsApplicationsByXid(Long xid) {
        return csApplicationsMapper.selectCsApplicationsByXid(xid);
    }

    /**
     * 查询抽取申请列表
     *
     * @param csApplications 抽取申请
     * @return 抽取申请
     */
    @Override
    public List<CsApplications> selectCsApplicationsList(CsApplications csApplications) {
        return csApplicationsMapper.selectCsApplicationsList(csApplications);
    }

    /**
     * 新增抽取申请
     *
     * @param csApplications 抽取申请
     * @return 结果
     */
    @Override
    public int insertCsApplications(CsApplications csApplications) {
        return csApplicationsMapper.insertCsApplications(csApplications);
    }

    /**
     * 修改抽取申请
     *
     * @param csApplications 抽取申请
     * @return 结果
     */
    @Override
    public int updateCsApplications(CsApplications csApplications) {
        return csApplicationsMapper.updateCsApplications(csApplications);
    }

    /**
     * 批量删除抽取申请
     *
     * @param xids 需要删除的抽取申请主键
     * @return 结果
     */
    @Override
    public int deleteCsApplicationsByXids(Long[] xids) {
        return csApplicationsMapper.deleteCsApplicationsByXids(xids);
    }

    /**
     * 删除抽取申请信息
     *
     * @param xid 抽取申请主键
     * @return 结果
     */
    @Override
    public int deleteCsApplicationsByXid(Long xid) {
        return csApplicationsMapper.deleteCsApplicationsByXid(xid);
    }


    @Override
    public List<CsCommittee> committeeList(CsCommittee csCommittee) {
        return csApplicationsMapper.committeeList(csCommittee);
    }

    @Override
    public R<Integer> deleteCommittee(String jId) {
        Integer integer = csApplicationsMapper.deleteCommittee(jId);

        if (integer > 0) {
            return R.ok(1, "success");
        }
        return R.fail("fail");
    }


    @Override
    @Transactional
    public R<List<ExpertEducateVO>> addApplications(ApplicationVO applicationVO) {
        // 判断是否存在(Committee表)
        Integer exit = csApplicationsMapper.getExit(applicationVO.getApplication().getiNumber());
        if (exit != 0) {
            // 删除所有关联子表
            deleteRelatedTables(applicationVO.getApplication().getiNumber());
        }
        // 新增抽取申请编号
        String code = createCode(service, CSRuleCode.BID_APPLICATIONS).getCode();

        // 查询所有专家
        List<String> collect;
        List<CsCondition> condition;
        List<Long> jIds;
        if (applicationVO.getAvoidUnit() == null) {
            //当进入这个判断时,代表我选中指定专家,所以这三个必为空
            collect = null;
            condition = null;
            jIds = null;
        } else {
            collect = applicationVO.getAvoidUnit().stream()
                    .map(CsAvoidingUnits::getUnitName)
                    .toList();

            condition = applicationVO.getCondition();

            jIds = applicationVO.getAvoidExpert().stream().map(CsAvoidingExpert::getjId).collect(Collectors.toList());
        }

        List<ExpertEducateVO> expertByAddressAndUnit = csApplicationsMapper.getExpertByAddressAndUnit(condition, collect, jIds);
        if (applicationVO.getApplication().getConfMethod() != 1) {
            //指定
            appoint(applicationVO);
            //前端并不需要这个结果
            return R.ok(expertByAddressAndUnit, "success");
        }

        //非指定
        // 新增
        add(applicationVO, expertByAddressAndUnit, code);

        Date date = new Date();
        long time = applicationVO.getApplication().getStartTime().getTime() - date.getTime();
        Random random = new Random();
        int fourDigitRandomNumber = random.nextInt(9000) + 1000;
        CorrelationData correlationData = new CorrelationData("2244" + fourDigitRandomNumber);

        //发送评标状态更改消息,根据抽取申请编号判断是否同一个抽取申请数据
        CsApplications csApplications = new CsApplications();
        csApplications.setApplicationNumber(code);
        String s1 = "";
        try {
            s1 = objectMapper.writeValueAsString(csApplications);
            System.out.println("s1 = " + s1);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
        template.convertAndSend(RabbitMqConfig.EVALUATION_BINDING_EXCHANGE, RabbitMqConfig.EVALUATION_BINDING_ROUTE, s1, msg -> {
            msg.getMessageProperties().setHeader("x-delay", time);
            msg.getMessageProperties().setContentType(MessageProperties.CONTENT_TYPE_JSON);
            return msg;
        }, correlationData);

        //结束时,更改项目状态为6
        long time2 = applicationVO.getApplication().getEndTime().getTime() - date.getTime();

        int fourDigitRandomNumber2 = random.nextInt(9000) + 1000;
        CorrelationData correlationData2 = new CorrelationData("2244" + fourDigitRandomNumber2);

        template.convertAndSend(RabbitMqConfig.CALIBRATE_BINDING_EXCHANGE, RabbitMqConfig.CALIBRATE_BINDING_ROUTE, s1, msgess -> {
            msgess.getMessageProperties().setHeader("x-delay", time2);
            msgess.getMessageProperties().setContentType(MessageProperties.CONTENT_TYPE_JSON);
            return msgess;
        }, correlationData2);

        //前端并不需要这个结果
        return R.ok(expertByAddressAndUnit);
    }

    private Integer deleteRelatedTables(String iNumber) {
        CompletableFuture<Integer> exceptionally = CompletableFuture.supplyAsync(() -> {
            csApplicationsMapper.deleteAvoidExpertByINumber(iNumber);
            csApplicationsMapper.deleteAvoidUnitByINumber(iNumber);
            csApplicationsMapper.deletePurchaseByINumber(iNumber);
            csApplicationsMapper.deleteConditionByINumber(iNumber);
            csApplicationsMapper.deleteApplicationByINumber(iNumber);
            csApplicationsMapper.deleteCommitteeByINumber(iNumber);
            return 1;
        }).exceptionally(ex -> {
            // 处理异常
            return null;
        });
        try {
            return exceptionally.get();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }
    }

    public void appoint(ApplicationVO applicationVO) {
        CsApplications application = applicationVO.getApplication();
        String s1 = application.getiNumber();

        applicationVO.getCommittee().forEach(s -> s.setiNumber(s1));

        // 新增抽取申请编号
        String code = createCode(service, CSRuleCode.BID_APPLICATIONS).getCode();
        application.setApplicationNumber(code);
        csApplicationsMapper.addApplications(application);

        CompletableFuture.runAsync(() -> {
            applicationVO.getPurchase().forEach(s -> s.setiNumber(s1));
            csApplicationsMapper.addPurchase(applicationVO.getPurchase());
        });

        CompletableFuture.runAsync(() -> {
            List<ExpertEducateVO> expertEducateVOS = applicationVO.getCommittee().stream().map(s -> {
                ExpertEducateVO educateVO = new ExpertEducateVO();
                educateVO.setName(s.getZjName());
                educateVO.setSex(s.getSex());
                educateVO.setIdCard(s.getIdCard());
                educateVO.setPhone(s.getPhone());
                educateVO.setjId(s.getjId());
                return educateVO;
            }).toList();
            csApplicationsMapper.addCommittee(expertEducateVOS, s1, code);
        });
    }

    public void add(ApplicationVO applicationVO, List<ExpertEducateVO> expertByAddressAndUnit, String code) {
        CsApplications application = applicationVO.getApplication();

        application.setApplicationNumber(code);
        csApplicationsMapper.addApplications(application);
        String iNumber = application.getiNumber();

        // 并行处理子表的新增
        List<CompletableFuture<?>> futures = new ArrayList<>();

        futures.add(CompletableFuture.runAsync(() -> {
            if (applicationVO.getAvoidExpert() != null && applicationVO.getAvoidExpert().size() > 0) {
                applicationVO.getAvoidExpert().forEach(s -> s.setiNumber(iNumber));
                csApplicationsMapper.addAvoidExpert(applicationVO.getAvoidExpert());
            }
        }));

        futures.add(CompletableFuture.runAsync(() -> {
            if (applicationVO.getAvoidUnit() != null && applicationVO.getAvoidUnit().size() > 0) {
                applicationVO.getAvoidUnit().forEach(s -> s.setiNumber(iNumber));
                csApplicationsMapper.addAvoidUnit(applicationVO.getAvoidUnit());
            }
        }));

        futures.add(CompletableFuture.runAsync(() -> {
            if (applicationVO.getPurchase() != null && applicationVO.getPurchase().size() > 0) {
                applicationVO.getPurchase().forEach(s -> s.setiNumber(iNumber));
                csApplicationsMapper.addPurchase(applicationVO.getPurchase());
            }
        }));

        futures.add(CompletableFuture.runAsync(() -> {
            List<CsCondition> condition = applicationVO.getCondition();
            if (condition != null && condition.size() > 0) {
                condition.forEach(s -> {
                    s.setiNumber(iNumber);
                    s.setaCode(code);
                });
                csApplicationsMapper.addCondition(condition);
            }
        }));

        futures.add(CompletableFuture.runAsync(() -> {
            if (expertByAddressAndUnit != null && expertByAddressAndUnit.size() > 0) {
                csApplicationsMapper.addCommittee(expertByAddressAndUnit, iNumber, code);
            }
        }));

    }


    @RabbitListener(queues = RabbitMqConfig.EVALUATION_BINDING_QUEUE)
    public void listenerKaiTime(CsApplications msg, Message message, Channel channel) {
        System.out.println("评标时间开始" + msg);
        //判断是否为同一个专家抽取编号(是否存在就行)

        //不存在,不是同一个抽取专家
        CsApplications exitApplication1 = csApplicationsMapper.isExitApplication(msg.getApplicationNumber());
        if (exitApplication1 == null) {
            return;
        }
        String exitApplication = exitApplication1.getiNumber();

        //同一个,更改项目状态
        csApplicationsMapper.changeTenderState(exitApplication, 5);
        try {
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (IOException e) {
            System.out.println("进入包包");
            throw new RuntimeException(e);
        }
    }

    @RabbitListener(queues = RabbitMqConfig.CALIBRATE_BINDING_QUEUE)
    public void listenerEndTime(CsApplications msg, Message message, Channel channel) {
        System.out.println("评标时间结束" + msg);
        //判断是否为同一个专家抽取编号(是否存在就行)

        //不存在,不是同一个抽取专家
        CsApplications exitApplication1 = csApplicationsMapper.isExitApplication(msg.getApplicationNumber());
        if (exitApplication1 == null && "".equals(exitApplication1.getiNumber())) {
            return;
        }
        String exitApplication = exitApplication1.getiNumber();
        csApplicationsMapper.changeTenderState(exitApplication, 6);
        try {
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (IOException e) {
            System.out.println("进入包包2222");
            throw new RuntimeException(e);
        }
    }

    @Override
    public R<CsApplications> getStartTimeAndEndTime(String iNumber) {
        CsApplications csApplications = csApplicationsMapper.getStartTimeAndEndTime(iNumber);
        return R.ok(csApplications);
    }

}